#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
#include "automata.h"
#include "longInt.h"
#include "dfa.h"

void nfaToDfa(t_table * t)
{
    while (t->states.dim > t->transitions.fils)                     
    {
        addStates(t->transitions.fils,t);      
//	printf("STATUS--------------------------------------------------------------------\n");
//        printTable(t);  
//        printStates2(&t->states); 

    }

//    printTable(t);  
//    printStates2(&t->states); 
    removeNodes(t);
//    printTable(t);  
//    printStates2(&t->states);
//    printStates2(&t->finalStates);
        
}

void addStates(int estadoNuevo, t_table * t)
{
     
    int procesoEstado,j=0,i;     
    t_int_vector * toca;     
    int indice=-1;  
    t_longInt destino;
    int pos;


     if((toca = malloc(sizeof(t_int_vector)*t->transitions.cols))== NULL)
        error(1,"Could not allocate memory. Shame on you.");
    
     for(i=0;i<t->transitions.cols;i++)
     {

       if((toca[i].vec=malloc(sizeof(int)*t->transitions.fils))== NULL)
                 error(1,"Could not allocate memory. Shame on you.");
       
       for(j=0;j<t->transitions.fils;j++)
               toca[i].vec[j]=-1;       
       toca[i].dim=0;

     }   
     

     
     j=0;
     while ((pos=getNextOne(t->states.vec[estadoNuevo],j))!=-1)
     {                           
           for(i=0;i<t->transitions.cols;i++)                                           
                     toca[i].vec[toca[i].dim++]=t->transitions.data[pos][i];                      
           
           j=pos+1;           
     }
   
   /*printf("los que toca son\n**********************************************************\n");
   for(j=0;j<t->transitions.fils;j++)
   {
   	  for(i=0;i<t->transitions.cols;i++)	
        	printf("\t %d",toca[i].vec[j]);   
 	  printf("\n");            
   }*/
   for(i=0;i<t->transitions.cols;i++)        
   {   
         reset(destino);
         processVector(t,&toca[i],destino); 
         if (isZero(destino))
    	 			indice=-1;		
         else        
         		indice=getStateIndex(t,destino);            
         t->transitions.data[t->transitions.fils][i]=indice;             
         free(toca[i].vec);
         
    }    
    
    addRow(t);    
    
    free(toca);
        
}


void addRow(t_table * t)
{
  int i,j;
  t->transitions.fils++;
 // Se jode con el realloc
 if (t->transitions.fils>=t->transitions.dimFils)
 {
  t->transitions.dimFils+=10;	
  if((t->transitions.data = realloc(t->transitions.data,t->transitions.dimFils*sizeof(int *)))== NULL)
        error(1,"Could not allocate memory. Shame on you.");  
  for(i=t->transitions.fils;i<t->transitions.dimFils;i++)         
  {
  	t->transitions.data[i]=malloc(sizeof(int)*t->transitions.cols);  	
  	for(j=0;j<t->transitions.cols;j++)	
  		t->transitions.data[i][j]=-1;
  }
  	 	
 }

}

void
processVector(t_table * t,t_int_vector * vector,t_longInt destino)
{
    int i;
        
    for(i=0;i<vector->dim;i++)			    
			if (vector->vec[i]!=-1)
    		longIntMerge(destino,t->states.vec[vector->vec[i]]);
       		
}
/*
void insertInResult(t_int_vector * vector,int num)
{
     int i, add=1;
     if (num==-1)
        add=0;
     for(i=0;i<vector->dim && add;i++)     
        if (vector->vec[i]==num)        
           add=0;        
        
     if (add)
        vector->vec[vector->dim++]=num;
     return;                                
}*/

void removeNodes(t_table * t)
{
     int i,j,h=0,f;
     t_longInt * aux;
     t_longInt_vector statesAux;
     t_longInt_vector statesAuxFin;
     
     markNodes(t,t->iniState);
     int ** replace;     
              
     if((replace = malloc(sizeof(int*)*2))==NULL)
                error(1,"Could not allocate memory. Shame on you.");                 
     if((replace[0] = malloc(sizeof(int)*t->transitions.fils))==NULL)
               error(1,"Could not allocate memory. Shame on you.");                 
     if((replace[1] = malloc(sizeof(int)*t->transitions.fils))==NULL)
               error(1,"Could not allocate memory. Shame on you.");                      
     
     createVec(&statesAux,t->states.dim);
     statesAux.dim=0;
     
     createVec(&statesAuxFin,t->finalStates.dim);
     statesAuxFin.dim=0; 
     
     for(i=0;i<(t->transitions.fils);i++)
     {     
         if  (t->transitions.data[i][t->transitions.cols-1]==-5) 
         {
             longIntCpy(statesAux.vec[statesAux.dim],t->states.vec[i]);
             if (i!=statesAux.dim)
             {
                  replace[0][h]=i;
                  replace[1][h++]=statesAux.dim;                  
                  for(j=0;j<t->transitions.cols;j++)
                      t->transitions.data[statesAux.dim][j]=t->transitions.data[i][j];
             }                                       
             t->transitions.data[statesAux.dim][t->transitions.cols-1]=-1;   
             statesAux.dim++;
                                                
             for(f=0;f<t->finalStates.dim;f++)
             	if (longIntCmp(t->states.vec[i],t->finalStates.vec[f]))
             		longIntCpy(statesAuxFin.vec[statesAuxFin.dim++],t->states.vec[i]);		
             }
     }    

     
     t->transitions.fils=statesAux.dim;
     //  Se deria achicar el espacio reservado para la matriz
     if((t->transitions.data = realloc(t->transitions.data,t->transitions.fils*sizeof(int *)))== NULL)
        error(1,"Could not allocate memory. Shame on you.");     
     
     if(statesAuxFin.dim>0)
     	if((statesAuxFin.vec = realloc(statesAuxFin.vec,statesAuxFin.dim*sizeof(t_longInt)))== NULL)
        	error(1,"Could not allocate memory. Shame on you.");     
      
     
     if(h>0)
     {
          for(i=0;i<(t->transitions.fils);i++)
            for(j=0;j<t->transitions.cols;j++)
               t->transitions.data[i][j]=changeValue(t->transitions.data[i][j],replace,h);

     }
     
     t->iniState=changeValue(t->iniState,replace,h);
     
     //adjustFinalStates(t);
     free(replace[1]);
     free(replace[0]);
     free(replace);     
     t->states.dim=statesAux.dim;
     aux=t->states.vec;
     t->states.vec=statesAux.vec;
     free(aux);
     t->finalStates.dim=statesAuxFin.dim;
     free(t->finalStates.vec);
     t->finalStates.vec=statesAuxFin.vec;
}
void markNodes(t_table * t,int state)
{

     int i,aux;
     t->transitions.data[state][t->transitions.cols-1]=-5;
     for(i=0;i<(t->transitions.cols-1);i++)
     {
         //where is pointing
         aux=t->transitions.data[state][i];
         //check that state
         if  (aux!=-1 && t->transitions.data[aux][t->transitions.cols-1]!=-5)
                  markNodes(t,aux);
     }

}
int changeValue(int value,int ** replace,int dim)
{
    int j;
    for(j=0;j<dim;j++)
    {   
       if (replace[0][j]==value)
          return replace[1][j];
    }      
    
    return value;
}
